//
//  NSObject+BrickSet.m
//  HappyRoom
//
//  Created by Captain Black on 2016/11/28.
//  Copyright © 2016年 Captain Black. All rights reserved.
//

#import "BrickSet.h"
#import "BrickSetServiceManager.h"

#include <dlfcn.h>
#include <mach-o/getsect.h>
#include <mach-o/loader.h>
#include <mach-o/dyld.h>

static NSMutableDictionary* _staticBindingServiceInfos = nil;

@implementation BrickSet

+ (void)registerClass:(Class)cls forService:(Protocol *)serviceProtocol {
    [[BrickSetServiceManager sharedInstance] registerClass:cls forService:serviceProtocol];
}

+ (void)unregisterService:(Protocol *)serviceProtocol {
    [[BrickSetServiceManager sharedInstance] unregisterService:serviceProtocol];
}

+ (id)instanceForService:(Protocol *)serviceProtocol {
    return [[BrickSetServiceManager sharedInstance] instanceForService:serviceProtocol];
}

+ (void)loadStaticBindingServicesByAddress:(const void*)addr {
    //1.根据符号找到所在的mach-o文件信息
    Dl_info info;
    dladdr(addr, &info);
    
    //2.读取__DATA中自定义的__BSServiceInfo数据
#ifndef __LP64__
    const struct mach_header *mhp = (struct mach_header*)info.dli_fbase;
    unsigned long serviceSize = 0;
    uint32_t *serviceMemory = (uint32_t*)getsectiondata(mhp, "__DATA", "__BSServiceInfo", &serviceSize);
#else /* defined(__LP64__) */
    const struct mach_header_64 *mhp = (struct mach_header_64*)info.dli_fbase;
    unsigned long serviceSize = 0;
    uint64_t *serviceMemory = (uint64_t*)getsectiondata(mhp, "__DATA", "__BSServiceInfo", &serviceSize);
#endif /* defined(__LP64__) */
    
    //3.遍历__BSServiceInfo中的协议数据
    unsigned long serviceCount = serviceSize/sizeof(struct BSServiceInfo);
    if (serviceCount > 0) {
        static dispatch_semaphore_t semaphore;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            semaphore = dispatch_semaphore_create(1);
        });
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);// 以信号量作为锁，确保线程安全
        {
            struct BSServiceInfo *infos = (struct BSServiceInfo*)serviceMemory;
            for(int idx = 0; idx < serviceCount; ++idx){
                NSString* serviceName = [NSString stringWithUTF8String:infos[idx].serviceName];
                NSString* impClassName = [NSString stringWithUTF8String:infos[idx].impClassName];
                uint priority = infos[idx].priority;
                
                if (serviceName.length <= 0 ||
                    impClassName.length <= 0) {
                    continue;
                }
                
                NSString* module = [[NSString stringWithUTF8String:info.dli_fname] lastPathComponent];
                NSLog(@"[BrickSet][load]静态绑定服务: %@, 实现类: %@, 优先级: %u, 模块:%@", serviceName, impClassName, priority, module);
                
                if (_staticBindingServiceInfos == nil) {
                    _staticBindingServiceInfos = [NSMutableDictionary dictionary];
                }
                if (_staticBindingServiceInfos[serviceName] != nil) {
                    NSString* clsName = _staticBindingServiceInfos[serviceName][@"impClassName"];
#ifdef DEBUG
                    NSAssert(NO, @"静态绑定服务冲突，%@ 已绑定 %@", serviceName, _staticBindingServiceInfos[serviceName][@"impClassName"]);
#endif
                    NSLog(@"[BrickSet][conflict]静态绑定服务: %@, 已存在实现类: %@, 将会覆盖为新实现类: %@",
                          serviceName, clsName, impClassName);
                }
                _staticBindingServiceInfos[serviceName] = @{
                    @"serviceName": serviceName,
                    @"impClassName": impClassName?:@"",
                    @"priority": @(priority)
                };
            }
        }
        dispatch_semaphore_signal(semaphore);
    }
}

+ (void)initStaticBindingServices {
    static BOOL hasInit = NO;
    NSAssert(!hasInit, @"静态绑定服务已经初始化，不要重复初始化！");
    hasInit = YES;
    
    static dispatch_semaphore_t semaphore;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        semaphore = dispatch_semaphore_create(1);
    });
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    {
        //按优先级排序
        NSMutableArray* temp = [_staticBindingServiceInfos.allValues mutableCopy];
        [temp sortUsingComparator:^NSComparisonResult(NSDictionary* _Nonnull obj1, NSDictionary* _Nonnull obj2) {
            uint p1;
            uint p2;
            p1 = [obj1[@"priority"] unsignedIntValue];
            p2 = [obj2[@"priority"] unsignedIntValue];
            
            // 倒序排序
            if (p1 == p2) {
                return NSOrderedSame;
            }
            else if (p1 > p2) {
                return NSOrderedAscending;
            }
            else {
                return NSOrderedDescending;
            }
        }];
        NSString* serviceName;
        NSString* impClassName;
        for (NSDictionary* info in temp) {
            serviceName = info[@"serviceName"];
            impClassName = info[@"impClassName"];
            
            Protocol* protocol = NSProtocolFromString(serviceName);
            // 注册服务
            [self registerClass:NSClassFromString(impClassName)
                     forService:protocol];
            // 调用服务实例，初始化服务
            [self instanceForService:protocol];
            
            NSLog(@"[BrickSet][init]静态绑定服务: %@, 实现类: %@, 优先级: %@", serviceName, impClassName, info[@"priority"]);
        }
        
        _staticBindingServiceInfos = nil;
    }
    dispatch_semaphore_signal(semaphore);
}

@end
